package games.eightPuzzle.heuristics;

import java.util.HashMap;

import games.eightPuzzle.states.*;

/**
 * @author avishl02
 * this class provides heuristic thats check if 2 tiles are at their
 * goal row/col but are reversed relative to their goal position,
 * if so, one of them will have to move up/down and allow the other 
 * to pass by, thus we can add 2 more steps to the Manhattan Distances
 * for every vertical/horizontal linear conflict
 */
public class LinearConflictHeuristic implements Heuristic{

	private HashMap<String, String> _verConflictsHolder = null;
	private HashMap<String, String> _horConflictsHolder = null;
	


	private CoordinatesHolder _cHolder = null; 

	//ctor
	public LinearConflictHeuristic(SlidingPuzzleState finalState){

		_cHolder = new CoordinatesHolder(finalState);

		_verConflictsHolder = new HashMap<String, String>();
		_horConflictsHolder = new HashMap<String, String>();
		
		//calculate all possible horizontal linear conflicts
		for(int i=0;i<finalState.getNumRows();i++){
			for(int j=0;j<finalState.getNumCols();j++){
				if (finalState.get(i, j)==0) continue;
				for(int k=j+1;k<finalState.getNumCols();k++){
					if (finalState.get(i, k)==0) continue;
					_horConflictsHolder.put(String.valueOf(finalState.get(i, k))+"#"+String.valueOf(finalState.get(i, j)), null);
					
					
				}
			}
		}

		//calculate all possible vertical confilcts
		for(int j=0;j<finalState.getNumCols();j++){
			for(int i=0;i<finalState.getNumRows();i++){
				if (finalState.get(i, j)==0) continue;
				for(int k=i+1;k<finalState.getNumRows();k++){
					if (finalState.get(k, j)==0) continue;
					_verConflictsHolder.put(String.valueOf(finalState.get(k, j))+"#"+String.valueOf(finalState.get(i, j)), null);
					
				
				}
			}
		}



	}

	/* (non-Javadoc)
	 * @see ai.ex1.heuristics.Heuristic#rank(ai.ex1.SlidingPuzzleState)
	 */
	public int rank(SlidingPuzzleState state) {
		int total = 0;
		int tmpInt;
		String tmpStr;
		//check for horizontal conflicts
		for(int i=0;i<state.getNumRows();i++){
			for(int j=0;j<state.getNumCols();j++){
				tmpInt = state.get(i, j);
				if (tmpInt ==0 || !_cHolder.isInRow(tmpInt, i))continue;
				tmpStr = String.valueOf(tmpInt)+"#";
				for(int k=j+1;k<state.getNumCols();k++){
					if (state.get(i, k)==0 || !_cHolder.isInRow(state.get(i, k), i))continue;
					if (_horConflictsHolder.containsKey(tmpStr+String.valueOf(state.get(i, k)))){
						++total;
					}
				}
			}
		}

		//check for vertical conflicts
		for(int j=0;j<state.getNumCols();j++){
			for(int i=0;i<state.getNumRows();i++){
				tmpInt = state.get(i, j);
				if (state.get(i, j)==0 || !_cHolder.isInCol(tmpInt, j)) continue;
				tmpStr = String.valueOf(tmpInt)+"#";
				for(int k=i+1;k<state.getNumRows();k++){
					if (state.get(k, j)==0 || !_cHolder.isInCol(state.get(k, j), j))continue;
					if (_verConflictsHolder.containsKey(tmpStr+String.valueOf(state.get(k, j)))){
						++total;
					}
				}
			}
		}
		

		return total*2;
	}
	

	

}
